
#include <BEntry>
#include "member_BEntry.h"

using namespace BWE;

#define member					(*(member_BEntry*)_ptr)
#define member_allocate()		_ptr = new member_BEntry(this)
#define member_release()		delete (member_BEntry*)_ptr

bool BEntry::Exist(const BString& fileName)
{
	Attrib attrib = BEntry::Check(fileName);
	return attrib != Attrib_None;
}
Attrib BEntry::Check(const BString& fileName)
{
	Attrib attrib = Attrib_None;
#ifdef _WIN32
	DWORD dwFileAttributes = GetFileAttributes(fileName.cstr());
	if (dwFileAttributes != INVALID_FILE_ATTRIBUTES)
		attrib = ConvertEntryAttrib(dwFileAttributes);
#endif

#ifdef linux
	struct stat st = { 0 };
	int ret = ::stat(fileName.cstr(), &st);
	if (ret >= 0)
		attrib = ConvertEntryAttrib(st.st_mode);
#endif

	return attrib;
}
BEntry* BEntry::Open(const BString& fileName)
{
#ifdef _WIN32
	WIN32_FIND_DATA EntryData;
	HANDLE hSearch = FindFirstFile(fileName.cstr(), &EntryData);
	if (hSearch == INVALID_HANDLE_VALUE)
		return 0;
	if (EntryData.dwFileAttributes == INVALID_FILE_ATTRIBUTES)
		return 0;
	BEntry* entry = new BEntry();
	entry->setName(fileName.name());
	entry_member(entry)->attrib = ConvertEntryAttrib(EntryData.dwFileAttributes);
	entry_member(entry)->path = fileName;
	entry_member(entry)->size = EntryData.nFileSizeLow;
	SYSTEMTIME st;
	FileTimeToSystemTime(&EntryData.ftLastWriteTime, &st);
	st.wHour = (st.wHour + 8) % 24;
	entry_member(entry)->date.set(st.wYear, st.wMonth, st.wDay);
	entry_member(entry)->time.set(st.wHour, st.wMinute, st.wSecond);
	return entry;
#endif

#ifdef linux
	struct stat st = {0};
	if(0 != ::stat(fileName.cstr(), &st))
		return 0;
	BEntry* entry = new BEntry();
	entry->setName(fileName.name());
	entry_member(entry)->attrib = ConvertEntryAttrib(st.st_mode);
	entry_member(entry)->path = fileName;
	entry_member(entry)->size = st.st_size;
	struct tm dtime = {0};
	localtime_r(&st.st_mtim.tv_sec, &dtime);
	entry_member(entry)->date.set(dtime.tm_year + 1900, dtime.tm_mon, dtime.tm_mday);
	entry_member(entry)->time.set(dtime.tm_hour, dtime.tm_min, dtime.tm_sec);	
	return entry;
#endif
	return 0;
}

BEntry::BEntry()
{
	member_allocate();
}
BEntry::~BEntry()
{
	member_release();
}

void BEntry::setAttrib(Attrib attrib)
{
	if (member.attrib != attrib)
	{
		member.attrib = attrib;
	}
}
Attrib BEntry::attrib() const
{
	return member.attrib;
}

void BEntry::setPath(const BString& path)
{
	if(member.path != path)
	{
		member.path = path;
	}
}
const BString& BEntry::path() const
{
	return member.path;
}

void BEntry::setDate(const BDate& date)
{
	member.date = date;
}
const BDate& BEntry::date() const
{
	return member.date;
}

void BEntry::setTime(const BTime& time)
{
	member.time = time;
}
const BTime& BEntry::time() const
{
	return member.time;
}

void BEntry::setSize(size_t size)
{
	member.size = size;
}
size_t BEntry::size() const
{
	return member.size;
}

bool BEntry::query(const BString& name, BValue& value) const
{
	if(member.attrib & Attrib_Link && name == "target")
	{
#ifdef linux
		char cstr[256];
		ssize_t size = readlink(member.path.cstr(), cstr, 256);
		if(size > 0)
		{
			cstr[size] = 0;
			return BValue(BString(cstr));
		}
#endif
	}
	return BObject::query(name, value);
}
